package com.xixibaby.core.mybatis;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.xixibaby.core.Join;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 自定义实现 innerjoin  left join 通用函数
 * @author : tomj
 * @since : 2019-02-27 19:31
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class JoinInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        // 先判断SELECT操作  如果不是select  直接放行
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
            return invocation.proceed();
        }
        BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
        //这是参数  看是否有mapper 参数   与 property参数   这俩个参数是必须的  关系到连接什么表   与当前表的什么属性关联
        Object paramObj = boundSql.getParameterObject();
        Join join = null;
        List<Join> list = new ArrayList<>();
        if(paramObj instanceof Map){
            for (Object arg : ((Map) paramObj).values()) {
                if (arg instanceof Join) {
                    join = (Join) arg;
                    break;
                }else if(arg instanceof List){
                    list = (List<Join>) arg;
                }
            }
        }else{
            return invocation.proceed();
        }

        String sql = boundSql.getSql();

        if(null == join && list.isEmpty()) {
            return invocation.proceed();
        }else if(null != join){
            sql = MessageFormat.format(sql,join.getTargetTable(),join.getTargetProperty(),join.getProperty(),String.join(",",join.getTargetFields()),join.getTable());
        }else if(!list.isEmpty()){
            List<String[]> fileds = new ArrayList<>();
            String collect = list.stream().map(join1 -> {
                String joinsql = join1.getJoinType() + " JOIN {0} {0} ON {0}.{1} = {2}.{3}";
                fileds.add(join1.getTargetFields());
                String formatJoinSql = MessageFormat.format(joinsql, join1.getTargetTable(), join1.getTargetProperty(), join1.getTable(), join1.getProperty());
                return formatJoinSql;
            }).collect(Collectors.joining("\n"));
            //组装所有的字段
            String fs = fileds.stream().flatMap(Stream::of).collect(Collectors.joining(","));
            sql = MessageFormat.format(sql,collect,fs);

        }
        metaObject.setValue("delegate.boundSql.sql", sql);
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
